package com.chzye.xhanddemos;

import static android.text.TextUtils.isEmpty;
import static com.rokid.gd.GdCommand.HIGH_TEMPERATURE_MODE;
import static com.rokid.gd.GdCommand.NORMAL_TEMPERATURE_MODE;
import static com.rokid.gd.GdCommand.toHexString;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.os.Build;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.PixelCopy;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.guide.sdk.GuideInterface;
import com.guide.sdk.bean.DataInternalParam;
import com.guide.sdk.bean.GuideUsbVideoMode;
import com.guide.sdk.bean.MTUserParam;
import com.guide.sdk.jni.NativeUtil;
import com.rokid.gd.GdCommand;
import com.rokid.gd.TempratureCallback;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;

/**
 * GD红外摄像头Java实现版本
 * 移植自rokid_apg_xhands项目的GdTemplateInfraCameraView
 */
public class GdTemplateInfraCameraViewJava extends SurfaceView implements SurfaceHolder.Callback, TempratureCallback {

    private static final String TAG = "GdTemplateInfraCameraViewJava";

    // 摄氏度
    public final static int UNIT_C_DEGREE = 0;
    // 华氏度
    public final static int UNIT_F_DEGREE = 1;

    private TextView temp_box_tv;
    private LinearLayout temp_bar_ll;

    private SurfaceHolder mSurfaceHolder;
    private Paint mPaint;
    private Paint mLowPaint;
    private Paint mHigPaint;
    private Paint mCenterPaint;

    private final GuideInterface mGuideInterface = new GuideInterface();
    private int mFrameCount = 0;
    private MTUserParam mCoinMTParam = new MTUserParam();
    private final Object mTempLock = new Object();

    // 原始红外宽高
    private static int WIDTH = 640;
    private static int HEIGHT = 512;

    // 真实屏幕跟模组的宽高比
    private static float WIDTHRATIO = 2;
    private static float HEIGHTRATIO = 2;

    // 范围框宽高
    private static int BOXWIDTH = 0;
    private static int BOXHEIGHT = 0;
    private static int CENTER_INDEX = WIDTH * HEIGHT / 2 + WIDTH / 2;
    private Bitmap mBitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);
    private Matrix matrix = new Matrix();

    private float[] mTemp = new float[WIDTH * HEIGHT];
    private short[] mSwapY16 = new short[WIDTH * HEIGHT];
    private byte[] mSwapParamLine = new byte[WIDTH * 2];
    private short[] mY16 = new short[WIDTH * HEIGHT];
    private byte[] mParamLine = new byte[WIDTH * 2];

    // 区域查询result
    private byte[] resultBytes;
    private int measureTempMode = -1; // 全图温度获取方式。-1：不可测温，0：温度矩阵，1：Y16+Param测温
    private boolean hasParamLine = false; // 参数行获取高低温 中心温

    // 温度显示相关的TextView引用
    private TextView mCenterTempTextView;
    private TextView mHigTempTextView, temp_bar_hig_tv;
    private TextView mLowTempTextView, temp_bar_low_tv;

    // 放大倍数
    private float multiple = 0.8f;
    // 放大级别
    private int zoom_level = 1;

    // 最热温度坐标
    private float higX;
    private float higY;

    // 最冷温度坐标
    private float lowX;
    private float lowY;

    // 打开模组
    private boolean isOpen;
    private boolean surfaceReleased = false;
    private Disposable mDisposable;
    private TempratureCallback temperatureCallback;

    int fps = 0;
    long lastTime = 0;
    long curTime = 0; // 当前时间戳

    private String centerTemp;
    // 1全屏测温 2范围测温
    private int mType = 1;

    private String averTemp;
    private String higTemp;
    private String lowTemp;
    // 0摄氏度 1华氏度
    private int TempUnit = 0;

    private static final float COEFF = 1.8f;
    private static final float OFFSET = 32.f;

    public GdTemplateInfraCameraViewJava(@NonNull Context context) {
        this(context, null);
    }

    public GdTemplateInfraCameraViewJava(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GdTemplateInfraCameraViewJava(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView() {
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
        paintInit();
        
        // 设置为不透明，提高性能
        setZOrderOnTop(false);
        getHolder().setFormat(android.graphics.PixelFormat.TRANSLUCENT);
    }

    private void paintInit() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setFilterBitmap(true);

        mLowPaint = new Paint();
        mLowPaint.setAntiAlias(true);
        mLowPaint.setStyle(Paint.Style.FILL);
        mLowPaint.setTextSize(24);
        mLowPaint.setStrokeWidth(2);

        mHigPaint = new Paint();
        mHigPaint.setAntiAlias(true);
        mHigPaint.setStyle(Paint.Style.FILL);
        mHigPaint.setTextSize(24);
        mHigPaint.setStrokeWidth(2);

        mCenterPaint = new Paint();
        mCenterPaint.setAntiAlias(true);
        mCenterPaint.setStyle(Paint.Style.FILL);
        mCenterPaint.setTextSize(24);
        mCenterPaint.setStrokeWidth(2);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mHigPaint.setColor(Color.parseColor("#ff0000"));
            mLowPaint.setColor(Color.parseColor("#112CF0"));
            mCenterPaint.setColor(Color.parseColor("#f4ea2a"));
        }
    }

    /**
     * 设置温度显示TextView的引用
     */
    public void setTemperatureTextViews(
            TextView centerTemp,
            TextView highTemp,
            TextView lowTemp,
            TextView tempBarHigh,
            TextView tempBarLow
    ) {
        this.mCenterTempTextView = centerTemp;
        this.mHigTempTextView = highTemp;
        this.mLowTempTextView = lowTemp;
        this.temp_bar_hig_tv = tempBarHigh;
        this.temp_bar_low_tv = tempBarLow;
    }

    public void setTempUnit(int unit) {
        TempUnit = unit;
    }

    public boolean modelIsOpen() {
        return isOpen;
    }

    /**
     * 打开模组，预览模组
     */
    public boolean autoOpen() {
        isOpen = mGuideInterface.open(getContext(), (callbackConfig) -> {
            WIDTH = callbackConfig.width;
            HEIGHT = callbackConfig.height;
            Log.i(TAG, "config WIDTH === " + WIDTH);
            Log.i(TAG, "config HEIGHT === " + HEIGHT);

            // 计算屏幕比例
            WIDTHRATIO = (float) getContext().getResources().getDisplayMetrics().widthPixels / WIDTH;
            HEIGHTRATIO = (float) getContext().getResources().getDisplayMetrics().heightPixels / HEIGHT;

            Log.i(TAG, "WIDTHRATIO === " + WIDTHRATIO);
            Log.i(TAG, "HEIGHTRATIO === " + HEIGHTRATIO);
            mSurfaceHolder.setFixedSize(WIDTH, HEIGHT);
            mBitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);
            mTemp = new float[WIDTH * HEIGHT];
            mSwapY16 = new short[WIDTH * HEIGHT];
            mSwapParamLine = new byte[WIDTH * 2];
            mY16 = new short[WIDTH * HEIGHT];
            mParamLine = new byte[WIDTH * 2];
            CENTER_INDEX = WIDTH * HEIGHT / 2 + WIDTH / 2;
            return null;
        });
        
        if (isOpen) {
            preview();
            setPalette();
            changeTemperatureModel(1);
            queryTemp();
            intervals(1000, number -> {
                queryRegionData();
                queryTemp();
            });
        } else {
            Log.e(TAG, "打开红外测温模组失败");
            Toast.makeText(getContext(), "打开模组失败", Toast.LENGTH_SHORT).show();
        }
        return isOpen;
    }

    public void preview() {
        mGuideInterface.startPreview((dataCallback) -> {
            if (!dataCallback.isSuccess) {
                return;
            }
            // 此处返回的是机芯返回的uyvy数据
            render(dataCallback.uyvy);
            synchronized (mTempLock) {
                hasParamLine = dataCallback.mode == GuideUsbVideoMode.YUV_PARAM || 
                              dataCallback.mode == GuideUsbVideoMode.X16_PARAM || 
                              dataCallback.mode == GuideUsbVideoMode.TEMP_PARAM_YUV || 
                              dataCallback.mode == GuideUsbVideoMode.Y16_PARAM_YUV || 
                              dataCallback.mode == GuideUsbVideoMode.Y16_PARAM || 
                              dataCallback.mode == GuideUsbVideoMode.TEMP_PARAM;
                              
                if (hasParamLine) {
                    System.arraycopy(dataCallback.paramLine, 0, mSwapParamLine, 0, dataCallback.paramLine.length);
                }

                if (dataCallback.mode == GuideUsbVideoMode.TEMP || 
                    dataCallback.mode == GuideUsbVideoMode.TEMP_PARAM || 
                    dataCallback.mode == GuideUsbVideoMode.TEMP_YUV || 
                    dataCallback.mode == GuideUsbVideoMode.TEMP_PARAM_YUV) {
                    System.arraycopy(dataCallback.y16, 0, mSwapY16, 0, dataCallback.y16.length);
                    measureTempMode = 0;
                } else {
                    boolean hasY16 = dataCallback.mode == GuideUsbVideoMode.Y16_PARAM || 
                                    dataCallback.mode == GuideUsbVideoMode.Y16 || 
                                    dataCallback.mode == GuideUsbVideoMode.Y16_PARAM_YUV || 
                                    dataCallback.mode == GuideUsbVideoMode.Y16_YUV;

                    if (hasY16) {
                        System.arraycopy(dataCallback.y16, 0, mSwapY16, 0, dataCallback.y16.length);
                    }
                    if (hasY16 && hasParamLine) {
                        measureTempMode = 1;
                    }
                }
            }
            
            mFrameCount++;
            Date nowDate = new Date();
            curTime = nowDate.getTime();
            if (curTime - lastTime > 1000) {
                Log.d(TAG, "preview: " + mFrameCount);
                fps = mFrameCount;
                mFrameCount = 0;
                lastTime = curTime;
            }

            if ((measureTempMode >= 0 || hasParamLine) && mFrameCount % 25 == 0 && 
                mCenterTempTextView != null && mCenterTempTextView.getVisibility() == View.VISIBLE) {
                post(() -> {
                    synchronized (mTempLock) {
                        System.arraycopy(mSwapY16, 0, mY16, 0, mSwapY16.length);
                        System.arraycopy(mSwapParamLine, 0, mParamLine, 0, mSwapParamLine.length);
                    }

                    centerTemp = "";
                    if (hasParamLine) {
                        DataInternalParam internalParam = mGuideInterface.getParamInfo(mParamLine);
                        if (internalParam != null) {
                            centerTemp = internalParam.getCursor_temp() / 10f + "";
                        }
                    } else {
                        if (measureTempMode == 1) {
                            mGuideInterface.measure(0, 0, mY16, mParamLine, mCoinMTParam, mTemp);
                            centerTemp = BigDecimal.valueOf(mTemp[CENTER_INDEX]).setScale(1, BigDecimal.ROUND_HALF_UP).floatValue() + "";
                        } else if (measureTempMode == 0) {
                            for (int i = 0; i < mY16.length; i++) {
                                mTemp[i] = mY16[i] / 10f;
                            }
                            centerTemp = BigDecimal.valueOf(mTemp[CENTER_INDEX]).setScale(1, BigDecimal.ROUND_HALF_UP).floatValue() + "";
                        }
                    }
                    
                    if (!isEmpty(centerTemp)) {
                        if (TempUnit == 1)
                            centerTemp = getF(Float.parseFloat(centerTemp));
                        // 显示中心温度
                        if (mCenterTempTextView != null) {
                            mCenterTempTextView.setText(String.format("%.1f°C", Float.parseFloat(centerTemp)));
                        }
                    }
                });
            }
        });
        Toast.makeText(getContext(), "开启预览", Toast.LENGTH_SHORT).show();
    }

    /**
     * 设置调色板
     */
    public void setPalette() {
        // 铁红
        boolean ret = mGuideInterface.sendControlCommand(GdCommand.getInstance().getThCommandByte());
        Log.i(TAG, "铁红 ret == " + ret);
        // 颜色条显示
        if (temp_bar_ll != null) {
            temp_bar_ll.setVisibility(View.VISIBLE);
        }
    }

    /**
     * 切换模式
     * @param hig true高温模式，false常规模式
     */
    public boolean switchMode(boolean hig) {
        if (isOpen) {
            return mGuideInterface.sendControlCommand(GdCommand.getInstance().getInstructByte(hig ? HIGH_TEMPERATURE_MODE : NORMAL_TEMPERATURE_MODE));
        }
        return false;
    }

    /**
     * 区域分析
     */
    private void changeRegion() {
        boolean ret1 = mGuideInterface.sendControlCommand(GdCommand.getInstance().getRgionalAnalysisByte());
        Log.i(TAG, "区域一分析 ret == " + ret1);
        // 分析框显示
        boolean ret2 = mGuideInterface.sendControlCommand(GdCommand.getInstance().getAnalysisBoxByte());
        Log.i(TAG, "分析框显示 ret == " + ret2);
    }

    /**
     * 区域分析页命令
     */
    private void queryRegionData() {
        if (!isOpen) return;

        byte[] bytes = new byte[1024];
        byte[] bytes1 = GdCommand.getInstance().getTemperature();
        boolean rets = mGuideInterface.sendQueryCommand(bytes1, bytes);

        List<Byte> byteList = new ArrayList<>();
        for (int i = 0; i < bytes.length; i++) {
            if (i == 0 && bytes[i] != 85) {
                return;
            }
            byteList.add(bytes[i]);
            if (bytes[i] == -16) break;
        }
        resultBytes = new byte[byteList.size()];
        for (int i = 0; i < byteList.size(); i++) {
            resultBytes[i] = byteList.get(i);
        }
    }

    /**
     * 设置温度
     */
    private void queryTemp() {
        if (resultBytes == null) return;

        if (resultBytes.length > 32) {
            String r = GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[25]}) + 
                      GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[26]});

            String len = GdCommand.getInstance().getTemperatureDec(r.replace(" ", ""));
            if (!isEmpty(len)) {
                lowTemp = len;
                if (TempUnit == 1)
                    lowTemp = getF(Float.parseFloat(lowTemp));
                if (mLowTempTextView != null) {
                    mLowTempTextView.setText("最低温：" + lowTemp);
                }
                if (temp_bar_low_tv != null) {
                    temp_bar_low_tv.setText(len);
                }
            }

            String lowx = GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[21]}) + 
                         GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[22]});
            String lowy = GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[23]}) + 
                         GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[24]});

            lowX = GdCommand.getInstance().getTemperatureXy(lowx.replace(" ", ""));
            lowY = GdCommand.getInstance().getTemperatureXy(lowy.replace(" ", ""));

            String re = GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[31]}) + 
                       GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[32]});

            String hig = GdCommand.getInstance().getTemperatureDec(re.replace(" ", ""));

            if (!isEmpty(hig)) {
                higTemp = hig;
                if (TempUnit == 1)
                    higTemp = getF(Float.parseFloat(higTemp));
                if (mHigTempTextView != null) {
                    mHigTempTextView.setText("最高温：" + higTemp);
                }
                if (temp_bar_hig_tv != null) {
                    temp_bar_hig_tv.setText(hig);
                }
            }

            String xr = GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[27]}) + 
                       GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[28]});
            String yr = GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[29]}) + 
                       GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[30]});

            higX = GdCommand.getInstance().getTemperatureXy(xr.replace(" ", ""));
            higY = GdCommand.getInstance().getTemperatureXy(yr.replace(" ", ""));

            if (temperatureCallback != null) {
                if (!isEmpty(centerTemp) && !isEmpty(len) && !isEmpty(hig)) {
                    temperatureCallback.callBack(Float.parseFloat(centerTemp), Float.parseFloat(hig), Float.parseFloat(len));
                }
            }
        }

        if (resultBytes.length > 40) {
            // 平均温度
            String r = GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[39]}) + 
                      GdCommand.getInstance().ByteArrayToString(new byte[]{resultBytes[40]});
            String ave = GdCommand.getInstance().getTemperatureDec(r.replace(" ", ""));

            if (!isEmpty(ave)) {
                averTemp = ave;
                if (TempUnit == 1)
                    averTemp = getF(Float.parseFloat(averTemp));
            }
        }
    }

    /**
     * 绘制
     */
    private void render(byte[] uyvy) {
        Canvas canvas = null;
        if (surfaceReleased) {
            return;
        }
        try {
            canvas = mSurfaceHolder.lockCanvas();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (canvas != null) {
            if (uyvy == null) {
                canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            } else {
                NativeUtil.uyvy2Bitmap(WIDTH, HEIGHT, uyvy, mBitmap);
                canvas.drawBitmap(mBitmap, matrix, mPaint);

                if (mLowTempTextView != null && !isEmpty(mLowTempTextView.getText())) {
                    // 最冷温度
                    canvas.drawText(mLowTempTextView.getText().toString().replace("最低温：", ""), lowX + 3, lowY + 15, mLowPaint);
                    // 画十字架
                    canvas.drawLine(lowX, lowY + 15, lowX, lowY - 15, mLowPaint);
                    canvas.drawLine(lowX - 12, lowY, lowX + 12, lowY, mLowPaint);
                }
                if (mHigTempTextView != null && !isEmpty(mHigTempTextView.getText())) {
                    // 最热温度
                    canvas.drawText(mHigTempTextView.getText().toString().replace("最高温：", ""), higX + 3, higY + 15, mHigPaint);
                    // 画十字架
                    canvas.drawLine(higX, higY + 15, higX, higY - 15, mHigPaint);
                    canvas.drawLine(higX - 12, higY, higX + 12, higY, mHigPaint);
                }

                if (mCenterTempTextView != null && !isEmpty(mCenterTempTextView.getText())) {
                    int centerX = WIDTH / 2;
                    int centerY = HEIGHT / 2;
                    // 中心温度
                    canvas.drawText(mCenterTempTextView.getText().toString().replace("中心温：", ""), centerX + 3, centerY + 15, mCenterPaint);
                    // 画十字架
                    canvas.drawLine(centerX, centerY + 15, centerX, centerY - 15, mCenterPaint);
                    canvas.drawLine(centerX - 12, centerY, centerX + 12, centerY, mCenterPaint);
                }
            }
        }
        try {
            mSurfaceHolder.unlockCanvasAndPost(canvas);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 最高温、最低温、中心温回调
     */
    public void setTemperatureCallback(TempratureCallback callback) {
        this.temperatureCallback = callback;
    }

    /**
     * 1全屏测温
     * 2范围测温
     */
    public void changeTemperatureModel(int model) {
        if (mType == model) return;

        mType = model;
        if (temp_box_tv != null) {
            temp_box_tv.setVisibility(model == 2 ? VISIBLE : INVISIBLE);
        }
        changeRegion();
        queryRegionData();
    }

    /**
     * 修改距离
     */
    public void changeDistance(int distance) {
        Log.i(TAG, "new int distance === " + distance);
        Log.i(TAG, "new W === " + toHexString(distance));
        boolean wControlRet = mGuideInterface.sendControlCommand(GdCommand.getInstance().getDistanceByte(toHexString(distance)));
        Log.i(TAG, "Distance ControlRet === " + wControlRet);
    }

    /**
     * 设置测温距离
     */
    public void setMeasureDistance(int distance) {
        changeDistance(distance);
    }



    /**
     * 设置分析区域
     */
    public void setAnalysisRegion(int x, int y, int width, int height) {
        changeTemperatureModel(2);
    }

    /**
     * 切换分析框显示
     */
    public void toggleAnalysisBox(boolean show) {
        if (show) {
            boolean ret = mGuideInterface.sendControlCommand(GdCommand.getInstance().getAnalysisBoxByte());
            Log.i(TAG, "Analysis box show ret == " + ret);
        }
    }

    /**
     * 切换色彩模式
     */
    public void switchColorMode(boolean isIronRed) {
        if (isIronRed) {
            setPalette();
        }
    }

    /**
     * 初始化红外摄像头
     */
    public void initInfraCamera() {
        autoOpen();
    }

    /**
     * 拍照
     */
    public boolean capturePhoto() {
        try {
            // 实际项目中这里应该捕获当前的红外图像
            Log.d(TAG, "Capturing infrared photo");
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Capture photo failed", e);
            return false;
        }
    }

    public void close() {
        if (mGuideInterface != null) {
            mGuideInterface.close();
            mGuideInterface.stopPreview();
        }
        cancel();
    }

    /**
     * 释放资源
     */
    public void release() {
        close();
    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        surfaceReleased = false;
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
        // Surface changed
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        surfaceReleased = true;
    }

    @Override
    public void callBack(float center, float hig, float low) {
        post(() -> {
            // 更新温度显示
            if (mCenterTempTextView != null) {
                mCenterTempTextView.setText(String.format("%.1f°C", center));
            }
            if (mHigTempTextView != null) {
                mHigTempTextView.setText(String.format("最高温：%.1f°C", hig));
            }
            if (mLowTempTextView != null) {
                mLowTempTextView.setText(String.format("最低温：%.1f°C", low));
            }
        });
    }

    /**
     * 每隔milliseconds毫秒后执行next操作
     */
    private void intervals(long milliseconds, final IRxNextListener next) {
        Observable observable = Observable.interval(milliseconds, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread());

        observable.subscribe(new Observer<Long>() {
            @Override
            public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {
                mDisposable = d;
            }

            @Override
            public void onNext(@NonNull Long number) {
                if (next != null) {
                    next.doNext(number);
                }
            }

            @Override
            public void onError(@NonNull Throwable e) {
                // Handle error
            }

            @Override
            public void onComplete() {
                // Complete
            }
        });
    }

    /**
     * 取消订阅
     */
    public void cancel() {
        if (mDisposable != null) {
            mDisposable.dispose();
            mDisposable = null;
            Log.e(TAG, "====定时器取消======");
        }
    }

    public interface IRxNextListener {
        void doNext(long number);
    }

    /**
     * 摄氏度转华氏度
     */
    public static String getF(float c) {
        return String.format("%.2f", c * COEFF + OFFSET);
    }

    // Getter methods
    public String getAverTemp() {
        return averTemp;
    }

    public String getHigTemp() {
        return higTemp;
    }

    public String getCenterTemp() {
        return centerTemp;
    }

    public String getLowTemp() {
        return lowTemp;
    }

    public int getGdModuleWidth() {
        return WIDTH;
    }

    public int getGdModuleHeight() {
        return HEIGHT;
    }
}